#ifndef QCCOMMON_H
#define QCCOMMON_H

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>

// visual studio upto 2013 does not support noexcept nor constexpr
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define QCLOG_NOEXCEPT throw()
#define QCLOG_CONSTEXPR
#else
#define QCLOG_NOEXCEPT noexcept
#define QCLOG_CONSTEXPR constexpr
#endif

namespace QcLog {

typedef enum {
    INFO,           // Analysis information directed to supporters
    DEBUG,          // Analysis debug information directed to developers
    WARNING,        // A warning, signalizing a deformity, without challenging the core operation
    CRITICAL,       // An critical, maybe that challenges the core operation
    FATAL           // Fatal error, the program execution has to be aborted
}Level;

static const QStringList QCLOG_LEVEL_STRINGLIST = {"info", "debg", "warn", "crit", "fatl"};

struct source_loc
{
    QCLOG_CONSTEXPR source_loc() = default;
    QCLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in)
        : filename{filename_in}
        , line{line_in}
        , funcname{funcname_in}
    {}
    QCLOG_CONSTEXPR source_loc(const source_loc &loc)
        : filename{loc.filename}
        , line{loc.line}
        , funcname{loc.funcname}
    {}

    QCLOG_CONSTEXPR bool empty() const QCLOG_NOEXCEPT
    {
        return line == 0;
    }
    const char *filename{nullptr};
    int line{0};
    const char *funcname{nullptr};
};

template <typename T>
class basic_raw_message
{
public:
    inline basic_raw_message(const T &msg)
        : data_(original_conversion(msg))
    {}
    inline basic_raw_message(const source_loc &loc, const T &msg)
        : loc_(loc)
        , data_(original_conversion(msg))
    {}

    /** Returns a pointer to the string data. */
    inline const QString data() const { return data_; }

    /** inline the string size. */
    inline int size() const { return data_.length(); }

protected:
    inline QString original_conversion(const char *message) { return QString(message); }
    inline QString original_conversion(const bool &message) { return message ? "true" : "false"; }
    inline QString original_conversion(const char &message) { return QString(message); }
    inline QString original_conversion(const int &message) { return QString::number(message); }
    inline QString original_conversion(const double &message) { return QString::number(message); }
    inline QString original_conversion(const QString &message) { return message; }
    inline QString original_conversion(const QByteArray &message) { return QString::fromUtf8(message); }
    inline QString original_conversion(const QJsonDocument &message) { return QString::fromUtf8(message.toJson(QJsonDocument::Indented)).insert(0, '\n'); }
    inline QString original_conversion(const QJsonObject &message) { return QString::fromUtf8(QJsonDocument(message).toJson(QJsonDocument::Indented)).insert(0, '\n'); }
    inline QString original_conversion(const QJsonArray &message) { return QString::fromUtf8(QJsonDocument(message).toJson(QJsonDocument::Indented)).insert(0, '\n'); }

private:
    const source_loc loc_{};
    const QString data_{};
};

} //namespace QcLog

#endif // QCCOMMON_H
